using AdminApiTemplate.Common.Exceptions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace AdminApiTemplate.Common.Helpers
{
    public class ConvertHelper
    {
        public static bool? GetBoolean(string input)
        {
            return GetBoolean(input, null);
        }

        public static bool? GetBoolean(string input, bool? defaultValue)
        {
            if (bool.TryParse(input, out bool temp))
            {
                return temp;
            }

            return defaultValue;
        }

        public static int? GetInt(string input)
        {
            return GetInt(input, null);
        }

        public static int? GetInt(string input, int? defaultValue)
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (int.TryParse(input, out int temp))
                {
                    return temp;
                }
            }

            return defaultValue;
        }

        public static long? GetLong(string input)
        {
            return GetLong(input, null);
        }

        public static long? GetLong(string input, long? defaultValue)
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (long.TryParse(input, out long temp))
                {
                    return temp;
                }
            }

            return defaultValue;
        }

        public static decimal? GetDecimal(string input)
        {
            return GetDecimal(input, null);
        }

        public static decimal? GetDecimal(string input, decimal? defaultValue)
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (decimal.TryParse(input, out decimal temp))
                {
                    return temp;
                }
            }

            return defaultValue;
        }

        public static DateTime? GetDateTime(string input)
        {
            return GetDateTime(input, null);
        }

        public static DateTime? GetDateTime(string input, DateTime? defaultValue)
        {
            if (DateTime.TryParse(input, out DateTime temp))
            {
                return temp;
            }

            return defaultValue;
        }

        public static DateTime? GetDateTimeExact(string input, string format)
        {
            return GetDateTimeExact(input, format, null);
        }

        public static DateTime? GetDateTimeExact(string input, string format, DateTime? defaultValue)
        {
            if (DateTime.TryParseExact(input, format, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime temp))
            {
                return temp;
            }

            return defaultValue;
        }

        public static decimal? ParseNumberFromString(string input)
        {
            return ParseNumberFromString(input, false);
        }

        public static decimal? ParseNumberFromString(string input, bool exact_mode)
        {
            var exact_input = "";
            if (exact_mode)
            {
                var matches = Regex.Matches(input, "([0-9]+[.]?[0-9]+)");
                if (matches.Count > 0)
                {
                    if (matches[0].Groups.Count > 1)
                    {
                        exact_input = matches[0].Groups[1].Value;
                    }
                }
            }
            else
            {
                var sb = new StringBuilder();
                foreach (var ch in input)
                {
                    if (!char.IsNumber(ch) && ch != '.')
                    {
                        continue;
                    }

                    sb.Append(ch);
                }
                exact_input = sb.ToString();
            }

            return GetDecimal(exact_input);
        }

        public static bool? ParseGenderFromString(string input)
        {
            if (!string.IsNullOrEmpty(input))
            {
                var males = new string[] { "1", "男", "true", "m", "male" };
                if (males.Any(a => input.ToLower().Contains(a)))
                {
                    return true;
                }

                var females = new string[] { "0", "女", "false", "f", "female" };
                if (females.Any(a => input.ToLower().Contains(a)))
                {
                    return false;
                }
            }

            return null;
        }

        public static bool? ParseBooleanFromString(string input)
        {
            if (!string.IsNullOrEmpty(input))
            {
                var yes = new string[] { "1", "真", "true", "yes" };
                if (yes.Any(a => input.ToLower().Contains(a)))
                {
                    return true;
                }

                var no = new string[] { "0", "假", "false", "no" };
                if (no.Any(a => input.ToLower().Contains(a)))
                {
                    return false;
                }
            }

            return null;
        }

        public static string GetDbString(int? val)
        {
            return val == null ? "NULL" : val.GetValueOrDefault().ToString();
        }

        public static string GetDbString(bool? val)
        {
            if (val == null)
            {
                return "NULL";
            }

            return val.Value ? "1" : "0";
        }

        public static string GetDbString(decimal? val)
        {
            return val == null ? "NULL" : val.GetValueOrDefault().ToString();
        }

        public static string GetDbString(DateTime? val)
        {
            return val == null ? "NULL" : "'" + val.GetValueOrDefault().ToString("yyyy/MM/dd HH:mm:ss") + "'";
        }

        public static string GetDbString(string val)
        {
            return val == null ? "NULL" : "'" + val + "'";
        }

        public static object GetVal(string fieldType, string val)
        {
            switch (fieldType)
            {
                default:
                    return val;
                case "Int32":
                    return GetInt(val);
                case "Int64":
                    return GetLong(val);
                case "Decimal":
                    return GetDecimal(val);
                case "DateTime":
                    return GetDateTime(val);
                case "Boolean":
                    return ParseBooleanFromString(val);
            }
        }

        public static T GetVal<T>(string val)
        {
            if (!string.IsNullOrEmpty(val))
            {
                var t = typeof(T);
                if (t == typeof(int) || t == typeof(int?))
                {
                    return (T)(object)GetInt(val).GetValueOrDefault();
                }

                else if (t == typeof(long) || t == typeof(long?))
                {
                    return (T)(object)GetLong(val).GetValueOrDefault();
                }

                else if (t == typeof(decimal) || t == typeof(decimal?))
                {
                    return (T)(object)GetDecimal(val).GetValueOrDefault();
                }

                else if (t == typeof(bool) || t == typeof(bool?))
                {
                    return (T)(object)ParseBooleanFromString(val);
                }

                else if (t == typeof(DateTime) || t == typeof(DateTime?))
                {
                    return (T)(object)GetDateTime(val).GetValueOrDefault();
                }

                else if (t == typeof(string))
                {
                    return (T)(object)val;
                }

                else
                {
                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "不支持的类型");
                }
            }

            return default(T);
        }

        public static object GetValFromDb(PropertyInfo tp, object dbVal)
        {
            if (dbVal != null)
            {
                var val = dbVal.ToString();
                var t = tp.PropertyType;
                if (t == typeof(int) || t == typeof(int?))
                {
                    return GetInt(val).GetValueOrDefault();
                }

                else if (t == typeof(long) || t == typeof(long?))
                {
                    return GetLong(val).GetValueOrDefault();
                }

                else if (t == typeof(decimal) || t == typeof(decimal?))
                {
                    return GetDecimal(val).GetValueOrDefault();
                }

                else if (t == typeof(bool) || t == typeof(bool?))
                {
                    return ParseBooleanFromString(val).GetValueOrDefault();
                }

                else if (t == typeof(DateTime) || t == typeof(DateTime?))
                {
                    return GetDateTime(val).GetValueOrDefault();
                }

                else if (t == typeof(string))
                {
                    return val;
                }

                else
                {
                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "不支持的类型");
                }
            }

            return null;
        }

        public static Dictionary<string, object> ToDictionary(object obj, bool includeNullValue = false)
        {
            var dict = new Dictionary<string, object>();
            if (obj != null)
            {
                var ttype = obj.GetType();
                var tps = ttype.GetProperties();
                foreach (var tp in tps)
                {
                    var val = tp.GetValue(obj, null);
                    if (val != null || includeNullValue)
                    {
                        dict[tp.Name] = val;
                    }
                }
            }

            return dict;
        }
    }
}
